<template>
	<div>
		<el-input
			id="textarea"
			style="width: 500px"
			placeholder="请输入您要合成的文本"
			maxlength="300"
			show-word-limit
			v-model="textarea"
			:rows="10"
			type="textarea">
		</el-input>
	</div>
	<!-- <div>
		<div>语速([0-100])：<input id="speed" value="50" /></div>
		<div>音量([0-100])：<input id="volume" value="50" /></div>
		<div>音高([0-100])：<input id="pitch" value="50" /></div>
		<div>发音人：<input id="vcn" value="xiaoyan" /></div>
	</div> -->
	<div>
		<el-button type="primary" id="controll_tts" @click="btnClick">{{
			btnStatusShow
		}}</el-button>

		<el-button type="primary" id="download_pcm" @click="download_pcm"
			>下载pcm</el-button
		>
		<el-button type="primary" id="download_wav" @click="download_wav"
			>下载wav</el-button
		>
	</div>
	<el-divider></el-divider>
	<div>
		<el-button type="primary" id="controll_tts" @click="generate"
			>非实时合成</el-button
		>
		<!-- <el-button type="primary" id="download_pcm" @click="generate_download"
			>下载音频</el-button
		> -->
	</div>
	<el-select v-model="typeAsr" style="width: 100px">
		<el-option value="1" label="百度">百度</el-option>
		<el-option value="2" label="阿里">阿里</el-option>
	</el-select>
	<el-select v-model="typeAduio" style="width: 100px">
		<el-option value="wav">wav</el-option>
		<el-option value="pcm">pcm</el-option>
	</el-select>
	<div id="audio"></div>
</template>

<script setup>
	import { ElMessage } from "element-plus";
	const APPID = "495edb9d";
	const API_KEY = "f0d3a00892b09e67a187db43131ece94";
	const API_SECRET = "NjRiZDkxN2RmODM0YWUzZDZhN2YzYzhi";
	import { ref, onMounted, onBeforeUnmount } from "vue";
	const textarea = ref("");
	const recBlob = ref(undefined);
	const audioUrl = ref(undefined);
	const audioPlayer = new AudioPlayer();
	const typeAsr = ref("1");
	const typeAduio = ref("wav");
	audioPlayer.onPlay = () => {
		changeBtnStatus("PLAY");
	};
	audioPlayer.onStop = (audioDatas) => {
		btnStatus.value === "PLAY" && changeBtnStatus("STOP");
	};
	const btnStatus = ref("UNDEFINED");
	const btnStatusShow = ref("讯飞实时合成");
	const changeBtnStatus = (status) => {
		btnStatus.value = status;
		if (status === "UNDEFINED") {
			btnStatusShow.value = "讯飞实时合成";
		} else if (status === "CONNECTING") {
			btnStatusShow.value = "正在合成";
		} else if (status === "PLAY") {
			btnStatusShow.value = "停止播放";
		} else if (status === "STOP") {
			btnStatusShow.value = "重新播放";
		}
	};
	const getWebSocketUrl = (apiKey, apiSecret) => {
		var url = "wss://tts-api.xfyun.cn/v2/tts";
		var host = location.host;
		var date = new Date().toGMTString();
		var algorithm = "hmac-sha256";
		var headers = "host date request-line";
		var signatureOrigin = `host: ${host}\ndate: ${date}\nGET /v2/tts HTTP/1.1`;
		var signatureSha = CryptoJS.HmacSHA256(signatureOrigin, apiSecret);
		var signature = CryptoJS.enc.Base64.stringify(signatureSha);
		var authorizationOrigin = `api_key="${apiKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"`;
		var authorization = btoa(authorizationOrigin);
		url = `${url}?authorization=${authorization}&date=${date}&host=${host}`;
		return url;
	};
	const encodeText = (text, type) => {
		if (type === "unicode") {
			let buf = new ArrayBuffer(text.length * 4);
			let bufView = new Uint16Array(buf);
			for (let i = 0, strlen = text.length; i < strlen; i++) {
				bufView[i] = text.charCodeAt(i);
			}
			let binary = "";
			let bytes = new Uint8Array(buf);
			let len = bytes.byteLength;
			for (let i = 0; i < len; i++) {
				binary += String.fromCharCode(bytes[i]);
			}
			return window.btoa(binary);
		} else {
			return Base64.encode(text);
		}
	};
	let ttsWS;
	const connectWebSocket = () => {
		const url = getWebSocketUrl(API_KEY, API_SECRET);
		if ("WebSocket" in window) {
			ttsWS = new WebSocket(url);
		} else if ("MozWebSocket" in window) {
			ttsWS = new MozWebSocket(url);
		} else {
			ElMessage.error("浏览器不支持WebSocket");
			return;
		}
		changeBtnStatus("CONNECTING");

		ttsWS.onopen = (e) => {
			audioPlayer.start({
				autoPlay: true,
				sampleRate: 16000,
				resumePlayDuration: 1000,
			});
			changeBtnStatus("PLAY");
			var text = textarea.value.trim() || "请输入您要合成的文本";

			var params = {
				common: {
					app_id: APPID,
				},
				business: {
					aue: "raw",
					auf: "audio/L16;rate=16000",
					vcn: "xiaoyan",
					speed: 50,
					volume: 50,
					pitch: 50,
					bgs: 1,
					tte: "UTF8",
				},
				data: {
					status: 2,
					text: encodeText(text, "UTF8"),
				},
			};
			ttsWS.send(JSON.stringify(params));
		};
		ttsWS.onmessage = (e) => {
			let jsonData = JSON.parse(e.data);
			// 合成失败
			if (jsonData.code !== 0) {
				console.error(jsonData);
				changeBtnStatus("UNDEFINED");
				return;
			}
			audioPlayer.postMessage({
				type: "base64",
				data: jsonData.data.audio,
				isLastData: jsonData.data.status === 2,
			});
			recBlob.value += jsonData.data.audio;
			if (jsonData.code === 0 && jsonData.data.status === 2) {
				ttsWS.close();
			}
		};
		ttsWS.onerror = (e) => {
			console.error(e);
		};
		ttsWS.onclose = (e) => {
			// console.log(e);
		};
	};
	const btnClick = () => {
		if (btnStatus.value === "UNDEFINED") {
			// 开始合成
			connectWebSocket();
		} else if (btnStatus.value === "CONNECTING") {
			// 停止合成
			changeBtnStatus("UNDEFINED");
			ttsWS?.close();
			audioPlayer.reset();
			return;
		} else if (btnStatus.value === "PLAY") {
			audioPlayer.stop();
		} else if (btnStatus.value === "STOP") {
			audioPlayer.play();
		}
	};
	const download_wav = () => {
		const blob = audioPlayer.getAudioDataBlob("wav");
		if (!blob) {
			ElMessage.error("请先合成语音");
			return;
		}
		let defaultName = new Date().getTime();
		let node = document.createElement("a");
		node.href = window.URL.createObjectURL(blob);
		node.download = `${defaultName}.wav`;
		node.click();
		node.remove();
	};
	const download_pcm = () => {
		const blob = audioPlayer.getAudioDataBlob("pcm");
		if (!blob) {
			ElMessage.error("请先合成语音");
			return;
		}
		let defaultName = new Date().getTime();
		let node = document.createElement("a");
		node.href = window.URL.createObjectURL(blob);
		node.download = `${defaultName}.pcm`;
		node.click();
		node.remove();
	};
	const generate = () => {
		var api = "/api/v1/sound";
		var onreadystatechange = function (xhr) {
			return function () {
				if (xhr.readyState == 4) {
					if (xhr.status == 200 && JSON.parse(xhr.response).code == 200) {
						// document.querySelector("#audio").innerHTML = "";
						audioUrl.value = JSON.parse(xhr.response).data;
						// var audio = document.createElement("audio");
						// audio.controls = true;
						// document.querySelector("#audio").appendChild(audio);
						// audio.src = audioUrl.value;
						// audio.play(); //这样就能播放了
						generate_download();
					} else {
						console.error("上传失败", xhr.status, xhr.responseText);
					}
				}
			};
		};
		var postData = JSON.stringify({
			way: typeAsr.value * 1,
			text: textarea.value.trim() || "请输入您要合成的文本",
			type: typeAduio.value,
			fileName: new Date().getTime(),
		});
		var xhr = new XMLHttpRequest();
		xhr.open("POST", api + "/synthesis");
		xhr.setRequestHeader("Content-Type", "application/json");
		xhr.onreadystatechange = onreadystatechange(xhr);
		xhr.send(postData);
	};
	const generate_download = () => {
		if (audioUrl.value) {
			//下载音频
			let defaultName = new Date().getTime();
			let node = document.createElement("a");
			node.href = audioUrl.value;
			node.download = `.wav`;
			node.click();
			node.remove();
		} else {
			ElMessage.error("请先合成语音");
		}
	};
</script>
<style scoped>
	.el-button {
		margin: 5px;
	}
</style>
